package com.tjmc.recruit.admin.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.plugin.excel.annotation.RequestExcel;
import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
import com.tjmc.recruit.admin.api.dto.PlatUserDTO;
import com.tjmc.recruit.admin.api.dto.UserTokenDTO;
import com.tjmc.recruit.admin.api.enums.PlatUserTypeEnum;
import com.tjmc.recruit.admin.api.entity.PlatformUserInfoEntity;
import com.tjmc.recruit.admin.api.feign.RemoteTokenService;
import com.tjmc.recruit.admin.api.feign.RemoteUserService;
import com.tjmc.recruit.admin.service.PlatformUserInfoService;
import com.tjmc.recruit.admin.service.SysPublicParamService;
import com.tjmc.recruit.common.core.constant.CommonConstants;
import com.tjmc.recruit.common.core.constant.SecurityConstants;
import com.tjmc.recruit.common.core.exception.ErrorCodes;
import com.tjmc.recruit.common.core.util.MsgUtils;
import com.tjmc.recruit.common.core.util.R;
import com.tjmc.recruit.common.log.annotation.SysLog;
import com.tjmc.recruit.common.security.annotation.Inner;
import com.tjmc.recruit.common.security.util.SecurityUtils;
import com.tjmc.recruit.finance.api.dto.AccountChangeDTO;
import com.tjmc.recruit.finance.api.entity.PlatformUserAccountEntity;
import com.tjmc.recruit.finance.api.enums.ChangeMehtodEnum;
import com.tjmc.recruit.finance.api.enums.UsageTypeEnum;
import com.tjmc.recruit.finance.api.feign.RemoteAccountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 平台用户信息表
 *
 * @author recruit
 * @date 2024-10-29 14:41:11
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/platUser")
@Tag(description = "platUser", name = "平台用户信息表管理")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class PlatformUserInfoController {
    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
    private final PlatformUserInfoService platformUserInfoService;
    private final RemoteAccountService remoteAccountService;
    private final RemoteTokenService remoteTokenService;
    private final RemoteUserService remoteUserService;
    private final SysPublicParamService sysPublicParamService;
    /**
     * 分页查询
     *
     * @param page             分页对象
     * @param platformUserInfo 平台用户信息表
     * @return
     */
    @Operation(summary = "分页查询", description = "分页查询")
    @GetMapping("/page")
    public R getPlatformUserInfoPage(@ParameterObject Page page, @ParameterObject PlatformUserInfoEntity platformUserInfo) {
        LambdaQueryWrapper<PlatformUserInfoEntity> wrapper = Wrappers.lambdaQuery();
        return R.ok(platformUserInfoService.page(page, wrapper));
    }


    /**
     * 通过条件查询平台用户信息表
     *
     * @param platformUserInfo 查询条件
     * @return R  对象列表
     */
    @Operation(summary = "通过条件查询", description = "通过条件查询对象")
    @GetMapping("/details")
    public R getDetails(@ParameterObject PlatformUserInfoEntity platformUserInfo) {
        return R.ok(platformUserInfoService.list(Wrappers.query(platformUserInfo)));
    }

    /**
     * 获取当前用户全部信息
     *
     * @return 用户信息
     */
    @GetMapping("/info")
    @Operation(summary = "获取当前用户全部信息", description = "获取当前用户全部信息")
    public R info() {
        String username = SecurityUtils.getUser().getUsername();
        PlatformUserInfoEntity userInfo = platformUserInfoService.getOne(Wrappers.<PlatformUserInfoEntity>query().lambda().eq(PlatformUserInfoEntity::getUsername, username));
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        return R.ok(platformUserInfoService.findUserInfo(userInfo));
    }

    /**
     * 根据ID查询用户信息
     *
     * @param id
     * @return
     */
    @Operation(summary = "根据ID查询用户信息", description = "根据ID查询用户信息")
    @GetMapping("/{id}")
    public R getUserById(@PathVariable("id") Long id) {
        PlatformUserInfoEntity userInfo = platformUserInfoService.getById(id);
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        return R.ok(userInfo);
    }

    /**
     * 注册用户
     *
     * @param userDto 用户信息
     * @return success/false
     */
    @Operation(summary = "注册用户", description = "注册用户")
    @Inner(value = false)
    @SysLog("注册用户")
    @PostMapping("/register/user")
    public R<Boolean> registerUser(@RequestBody PlatUserDTO userDto) {
        return platformUserInfoService.registerUser(userDto);
    }


    @Operation(summary = "小程序用户登录", description = "小程序用户登录")
    @Inner(value = false)
    @SysLog("小程序用户登录或注册")
    @PostMapping("/wx_login")
    public R wxLogin(@RequestBody Map<String, String> requestBody) {
        String code = requestBody.get("code");
        String idString = requestBody.get("id");
        String encryptedData = requestBody.get("encryptedData"); // 前端传回的加密数据
        String iv = requestBody.get("iv"); // 前端传回的初始向量

        if (code == null) {
            return R.failed("code 不能为空");
        }

        if (idString == null) {
            return R.failed("id 不能为空");
        }
        // 通过 code、id 和 description 获取 openid 和 session_key
        Map<String, String> authResult = platformUserInfoService.loginWithWeChat(code);

        if (authResult == null || !authResult.containsKey("openid")) {
            return R.failed("微信登录失败");
        }

        String openid = authResult.get("openid");
        String sessionKey = authResult.get("session_key"); // 获取 session_key

        // 使用 session_key、encryptedData 和 iv 解密获取手机号
        String phoneNumber = platformUserInfoService.decryptPhoneNumber(sessionKey, encryptedData, iv);
        if (StrUtil.isBlank(phoneNumber)) {
            return R.failed("获取手机号失败");
        }
        List<PlatformUserInfoEntity> userInfoEntityList = platformUserInfoService.
                list(Wrappers.<PlatformUserInfoEntity>query().lambda()
                        .eq(PlatformUserInfoEntity::getPhone, phoneNumber));
        //这里如果存在多个，默认返回个人用户
        // 如果存在多个相同手机号的用户，且没有个人用户，则允许新创建个人账号即返回null
        PlatformUserInfoEntity userInfo;
        if (userInfoEntityList.size() > 1) {
            userInfo = userInfoEntityList.stream().filter(user -> user.getUserType()
                            .equals(PlatUserTypeEnum.PERSONAL)).findFirst()
                    .orElse(null);
        } else if (userInfoEntityList.size() == 1) {
            userInfo = userInfoEntityList.get(0);
        } else {
            // 空
            userInfo = null;
        }
        UserTokenDTO userTokenDTO = new UserTokenDTO();
        if (userInfo == null) {
            //使用手机号注册用户
            PlatUserDTO platUserDTO = new PlatUserDTO();
            platUserDTO.setPhone(phoneNumber);
            platUserDTO.setPassword("123456");
            //用户名为手机号
            platUserDTO.setUsername(phoneNumber);
            //默认个人用户
            platUserDTO.setUserType(PlatUserTypeEnum.PERSONAL);
            platUserDTO.setWxOpenid(openid);
            platformUserInfoService.registerUser(platUserDTO);
            userTokenDTO.setUsername(phoneNumber);
        } else {
            userTokenDTO.setUsername(userInfo.getUsername());
            if (StrUtil.isBlank(userInfo.getWxOpenid())) {
                userInfo.setWxOpenid(openid);
            }
            platformUserInfoService.updateById(userInfo);
        }
        //返回token信息
        Map<String, Object> map = new HashMap<>();
        R r = remoteTokenService.generateToken(userTokenDTO);
        System.out.println("accessToken = " + r.getData());
        map.put("accessToken", r.getData());
        map.put("tokenType", "Bearer");
        map.put("openId", openid);
        return R.ok(map);
    }

    /**
     * 新增企业子账号
     *
     * @param platformUserInfo 平台用户信息表
     * @return R
     */
    @Operation(summary = "新增企业子账号", description = "新增企业子账号")
    @SysLog("新增企业子账号")
    @PostMapping
    public R save(@RequestBody PlatformUserInfoEntity platformUserInfo) {
        //查询创建者对应账号是否存在
        if (StrUtil.isBlank(platformUserInfo.getCreateBy())) {
            return R.failed("创建者不能为空");
        }
        PlatformUserInfoEntity userInfo = platformUserInfoService.getOne(Wrappers.<PlatformUserInfoEntity>lambdaQuery()
                .eq(PlatformUserInfoEntity::getId, platformUserInfo.getCreateBy()));
        if (userInfo == null) {
            return R.failed("创建失败，创建者用户不存在");
        }
        //1. 创建者是否为企业主账号
        if (!userInfo.getAccountType().equals(PlatUserTypeEnum.MAIN)) {
            //如果不是主账号不可创建
            return R.failed("创建失败，创建者不是主账号");
        }
        if (userInfo.getCompanyId() == null) {
            return R.failed("创建者账号未关联到企业");
        }
        // 2. 用户类型==企业，账号类型==子账
        if (!platformUserInfo.getAccountType().equals(PlatUserTypeEnum.SUB)) {
            return R.failed("创建失败，账号类型错误");
        }
        // 3. 子账号用户名不能与主账号相同
        if (platformUserInfo.getUsername().equals(userInfo.getUsername())) {
            return R.failed("用户名不可与主账号相同");
        }
        if (platformUserInfo.getPhone().equals(userInfo.getPhone())) {
            return R.failed("手机号不可与主账号相同");
        }
        // 4. 企业子账号剩余数量
        R<PlatformUserAccountEntity> accountInfo = remoteAccountService.getAccountInfo(String.valueOf(userInfo.getId()), SecurityConstants.FROM_IN);
        PlatformUserAccountEntity account = accountInfo.getData();
        if (account == null) {
            return R.failed("未查询到账户信息");
        }
        if (account.getSubAccountNum() < 1) {
            return R.failed("子账户数量不足，无法创建");
        }
        platformUserInfo.setPassword(ENCODER.encode(platformUserInfo.getPassword()));
        platformUserInfo.setCompanyId(userInfo.getCompanyId());
        platformUserInfo.setCompanyName(userInfo.getCompanyName());
        // 5. 扣减子账号数量
        AccountChangeDTO accountChangeDTO = new AccountChangeDTO();
        accountChangeDTO.setUsageType(UsageTypeEnum.CREATE_SUB_ACCOUNT);
        accountChangeDTO.setChangeMethod(ChangeMehtodEnum.SUBTRACT.name());
        accountChangeDTO.setAccountId(account.getAccountId());
        accountChangeDTO.setChangeValue(BigDecimal.ONE);
        R r = remoteAccountService.changeAccountInfo(accountChangeDTO, SecurityConstants.FROM_IN);
        if (r.getCode() != CommonConstants.SUCCESS){
            return R.failed("扣减账户子账户数量失败");
        }
        boolean save = platformUserInfoService.save(platformUserInfo);
        if (!save){
            return R.failed("新增子账号失败");
        }
        return R.ok();
    }

    /**
     * 通过企业ID查询子账号列表
     *
     * @return
     */
    @Operation(summary = "查询企业子账号", description = "查询企业子账号")
    @SysLog("查询企业子账号")
    @GetMapping("/sub")
    public R getSubAccount() {
        String name = SecurityUtils.getUser().getName();
        PlatformUserInfoEntity userInfo = platformUserInfoService.getOne(Wrappers.<PlatformUserInfoEntity>lambdaQuery().eq(PlatformUserInfoEntity::getUsername, name));
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        List<PlatformUserInfoEntity> userList = platformUserInfoService.list(new LambdaQueryWrapper<PlatformUserInfoEntity>()
                .eq(PlatformUserInfoEntity::getAccountType, PlatUserTypeEnum.SUB)
                .eq(PlatformUserInfoEntity::getCompanyId, userInfo.getCompanyId()));
        return R.ok(userList);
    }

    @Operation(summary = "修改企业子账号", description = "修改企业子账号")
    @SysLog("修改企业子账号")
    @PutMapping("/sub/update")
    public R updateSubAccount(@RequestBody PlatformUserInfoEntity platformUserInfo) {
        return R.ok(platformUserInfoService.updateById(platformUserInfo));
    }

    @Operation(summary = "删除企业子账号", description = "删除企业子账号")
    @SysLog("删除企业子账号")
    @DeleteMapping("/sub/delete/{id}")
    public R deleteSubAccount(@PathVariable Long id) {
        PlatformUserInfoEntity userInfo = platformUserInfoService.getById(id);
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        return R.ok(platformUserInfoService.removeById(userInfo));
    }

    /**
     * 修改平台用户信息表
     *
     * @param platformUserInfo 平台用户信息表
     * @return R
     */
    @Operation(summary = "修改平台用户信息表", description = "修改平台用户信息表")
    @SysLog("修改平台用户信息表")
    @PutMapping
    public R updateById(@RequestBody PlatformUserInfoEntity platformUserInfo) {
        return R.ok(platformUserInfoService.updateById(platformUserInfo));
    }

    /**
     * 通过id删除平台用户信息表
     *
     * @param ids id列表
     * @return R
     */
    @Operation(summary = "通过id删除平台用户信息表", description = "通过id删除平台用户信息表")
    @SysLog("通过id删除平台用户信息表")
    @DeleteMapping
    public R removeById(@RequestBody Long[] ids) {
        return R.ok(platformUserInfoService.removeBatchByIds(CollUtil.toList(ids)));
    }

    /**
     * 校验手机号是否注册-公开
     *
     * @param phone 手机号
     * @return
     */
    @Inner(value = false)
    @GetMapping("/checkPhone/{phone}")
    @Operation(summary = "校验手机号是否注册-公开", description = "校验手机号是否注册-公开")
    public R checkPhone(@PathVariable String phone) {
        List<PlatformUserInfoEntity> userList = platformUserInfoService.list(new LambdaQueryWrapper<PlatformUserInfoEntity>().eq(PlatformUserInfoEntity::getPhone, phone));
        if (userList.isEmpty()) {
            return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_PHONE_UNREGISTERED, phone));
        }
        return R.failed("手机号已注册");
    }

    /**
     * 查询用户名是否可用
     *
     * @param username 用户名
     * @return
     */
    @GetMapping("/checkUserName/{username}")
    @Operation(summary = "查询用户名是否可用", description = "查询用户名是否可用")
    public R checkUserName(@PathVariable String username) {
        List<PlatformUserInfoEntity> infoEntityList = platformUserInfoService.list(new LambdaQueryWrapper<PlatformUserInfoEntity>().eq(PlatformUserInfoEntity::getUsername, username));
        if (infoEntityList.isEmpty()) {
            return R.ok(Boolean.TRUE);
        }
        return R.failed(Boolean.FALSE);
    }

    /**
     * 修改手机号
     *
     * @param phone   变更后手机号
     * @param valCode 验证码
     * @return
     */
    @PutMapping("/changePhone")
    @Operation(summary = "修改用户手机号", description = "修改用户手机号")
    public R changePhone(@ParameterObject String phone, @ParameterObject String newPhone, @ParameterObject String valCode, @ParameterObject Boolean sync) {
        return R.ok(platformUserInfoService.changePhone(phone, newPhone, valCode, sync));
    }

    /**
     * 修改用户微信号
     *
     * @param wxUserNo 微信号
     * @return
     */
    @PutMapping("/changeWxUserNo")
    @Operation(summary = "修改用户微信号", description = "修改用户微信号")
    public R changeWxUserNo(@ParameterObject String wxUserNo) {
        return R.ok(platformUserInfoService.changeWxUserNo(wxUserNo));
    }

    /**
     * 修改用户名或密码
     *
     * @param userName    变更后用户名
     * @param valCode     验证码
     * @param newPassword 新密码
     * @return
     */
    @PutMapping("/changeUserNameOrPassword")
    @Operation(summary = "修改用户名或密码", description = "修改用户名或密码")
    public R changePhone(@ParameterObject String userName, @ParameterObject String valCode, @ParameterObject String newPassword) {
        return R.ok(platformUserInfoService.changeUserNameOrPassword(userName, valCode, newPassword));
    }

    /**
     * 重置密码
     *
     * @param id
     * @return
     */
    @PutMapping("/resetPassword/{id}")
    @Operation(summary = "重置密码", description = "重置密码")
    public R resetPassword(@PathVariable Long id) {
        PlatformUserInfoEntity userInfo = platformUserInfoService.getById(id);
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        return R.ok(platformUserInfoService.resetPassword(userInfo));
    }

    /**
     * 修改账号状态
     *
     * @param id
     * @param status
     * @return
     */
    @PutMapping("/resetAccountStatus/{id}")
    @Operation(summary = "修改账号状态", description = "修改账号状态")
    public R resetAccountStatus(@PathVariable Long id, @ParameterObject String status) {
        PlatformUserInfoEntity userInfo = platformUserInfoService.getById(id);
        if (userInfo == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
        }
        userInfo.setStatus(status);
        return R.ok(platformUserInfoService.updateById(userInfo));
    }

    @Operation(summary = "切换用户", description = "切换用户")
    @SysLog("切换用户")
    @GetMapping("/exchange")
    public R exchange(@ParameterObject String code) {
        if (StrUtil.isBlank(code)) {
            return R.failed("凭证Code不能为空");
        }
        // 1. 查询当前登录用户信息
        R<PlatformUserInfoEntity> platformedUser = remoteUserService.platformUser(SecurityUtils.getUser().getName(), SecurityConstants.FROM_IN);
        if (platformedUser.getCode() != CommonConstants.SUCCESS){
            return R.failed("查询用户信息失败");
        }
        PlatformUserInfoEntity userInfo = platformedUser.getData();
        if (StrUtil.isBlank(userInfo.getPhone())) {
            return R.failed("当前用户手机号为空，无法切换");
        }
        // 2. 通过手机号判断是否存在可切换用户
        List<PlatformUserInfoEntity> userList = platformUserInfoService.list(new LambdaQueryWrapper<PlatformUserInfoEntity>()
                .eq(PlatformUserInfoEntity::getPhone, userInfo.getPhone()));
        if (userList.isEmpty()) {
            return R.failed("手机号未注册");
        }
        //筛选出可切换用户列表
        Map<String, Object> map = new HashMap<>();
        UserTokenDTO tokenDTO = new UserTokenDTO();
        List<PlatformUserInfoEntity> exchangeList = userList.stream().filter(user -> !user.getUserType().equals(userInfo.getUserType())).toList();
        if (exchangeList.isEmpty()) {
            // 1. 如果当前是企业用户，则用企业账号的信息创建个人用户账号返回
            if (userInfo.getUserType().equals(PlatUserTypeEnum.COMPANY)) {
                //登录微信
                Map<String, String> authResult = platformUserInfoService.loginWithWeChat(code);
                if (authResult == null || !authResult.containsKey("openid")) {
                    return R.failed("微信登录失败");
                }
                String openid = authResult.get("openid");
                PlatUserDTO platUserDTO = new PlatUserDTO();
                platUserDTO.setUsername(userInfo.getPhone());
                platUserDTO.setPassword(userInfo.getPassword());
                platUserDTO.setUserType(PlatUserTypeEnum.PERSONAL);
                platUserDTO.setWxOpenid(openid);
                platUserDTO.setPhone(userInfo.getPhone());
                R<Boolean> registered = platformUserInfoService.registerUser(platUserDTO);
                if (registered.getCode() != CommonConstants.SUCCESS) {
                    return R.failed("切换失败");
                }
                //返回token信息
                tokenDTO.setUsername(platUserDTO.getUsername());
                R r = remoteTokenService.generateToken(tokenDTO);
                map.put("access_token", r.getData());
                return R.ok(map);
            }
            return R.failed("不存在可切换用户");
        }
        // 3. 返回切换后用户信息
        if (exchangeList.size() == 1) {
            PlatformUserInfoEntity platformUserInfo = exchangeList.get(0);
            if (StrUtil.isBlank(platformUserInfo.getWxOpenid())) {
                //登录微信
                Map<String, String> authResult = platformUserInfoService.loginWithWeChat(code);
                if (authResult == null || !authResult.containsKey("openid")) {
                    return R.failed("微信登录失败");
                }
                String openid = authResult.get("openid");
                platformUserInfo.setWxOpenid(openid);
                platformUserInfoService.updateById(platformUserInfo);
            }
            tokenDTO.setUsername(platformUserInfo.getUsername());
            R r = remoteTokenService.generateToken(tokenDTO);
            map.put("access_token", r.getData());
            return R.ok(map);
        } else {
            return R.failed("存在多个可切换账号，无法切换");
        }
    }


    /**
     * 导出excel 表格
     *
     * @param platformUserInfo 查询条件
     * @param ids              导出指定ID
     * @return excel 文件流
     */
    @ResponseExcel
    @GetMapping("/export")
    public List<PlatformUserInfoEntity> exportExcel(PlatformUserInfoEntity platformUserInfo, Long[] ids) {
        return platformUserInfoService.list(Wrappers.lambdaQuery(platformUserInfo).in(ArrayUtil.isNotEmpty(ids), PlatformUserInfoEntity::getId, ids));
    }

    /**
     * 导入excel 表
     *
     * @param platformUserInfoList 对象实体列表
     * @param bindingResult        错误信息列表
     * @return ok fail
     */
    @PostMapping("/import")
    public R importExcel(@RequestExcel List<PlatformUserInfoEntity> platformUserInfoList, BindingResult bindingResult) {
        return R.ok(platformUserInfoService.saveBatch(platformUserInfoList));
    }

}
